//xlang Source, Name:BusinessClt.x 
//Date: Mon Apr 03:24:33 2024 

class BusinessClt: AsyncInput{
    static String proxy_serverHost, key;
    static int proxy_serverPort;
    
    static String serverHost;
    static int serverPort;
    static int timeout = 90000, buffersize = 1024, thread = 2, proxy_idlePort = 15370;
    
    Client _client ;
	Unsi _unsi = new Unsi();
    
    Map<int, long> ctx_map = new Map<int, long>();
    
    public static String getKey(){
        return key;
    }
    
    public static bool loadConfigure(){
        FileStream.FileInputStream fis = nilptr;
        try{
            File fp = new File(_system_.getAppDirectory().appendPath("proxy_client.json"));
            if (fp.exists()){
                fis =  new FileStream.FileInputStream(fp);
                JsonObject json = new JsonObject(new String(fis.read()));
                proxy_serverHost = json.getString("proxy_serverHost");
                key = json.getString("key");
                proxy_serverPort = json.getInt("proxy_serverPort");
                serverHost = json.getString("serverHost");
                serverPort = json.getInt("serverPort");
                if (json.has("timeout")){
                    timeout = json.getInt("timeout");
                }
                if (json.has("buffersize")){
                    buffersize = json.getInt("buffersize");
                }
                if (json.has("seed")){
                    seed = json.getInt("seed");
                }
                if (json.has("proxy_idlePort")){
                    proxy_idlePort = json.getInt("proxy_idlePort");
                }
                if (buffersize < 1024){
                    buffersize = 1024;
                }
                if (json.has("thread")){
                    thread = json.getInt("thread");
                }
                if (thread < 1){
                    thread = 1;
                }
                return proxy_serverHost != nilptr && serverHost != nilptr;
            }
        }catch(Exception e){
        
        }finally{
            if (fis != nilptr){
                fis.close();
            }
        }
        return false;
    }
    
    public bool start(){
        _client = new Client(this);
        // 创建通用网络服务接口, 异步回调接口为this, 端口随便填个, 超时
		if (_unsi.create(this, Unsi.UNSI_TCP, proxy_idlePort, timeout) == false){
			//System.out.print("创建服务器失败\n");
            return false;
		} 
        // 线程数,  缓冲区大小为,  超时
        _unsi.config(thread, buffersize, timeout);
        
        //启动服务
        if (_unsi.start() == false){
			//System.out.print("开启服务器失败\n");
		}else{
            // 这里填你服务器的地址 和端口, 
            if (_client.create(proxy_serverHost, proxy_serverPort)){
                return true;
            }
		}
        return false;
    }
    
	void notify(AsyncOutput output, int type, long bind, bool bsucceed, long context,int length)override{
        // type 1 为新建连接， 没有成功的时候, 清除缓冲器，并阻断连接
        if (type == 1 && bsucceed == false){
            _client.bind(0, bind);
        }
	}
    
    static byte seed = 8;
    // 异或加密
    static void encrypt(byte [] data,int offset, int len){
        for (int i : len){
            data[offset + i] = data[offset + i] ^ seed;
        }
    }
    
    /** 服务器通过RCP通信写数据, id为链接标号 */
    public void write(int id, byte [] data, int offset, int len){
        // 加密数据
        encrypt(data, offset, len);
        
        long lctx = 0;
        // 寻找id对应的 本地链接context
        synchronized(ctx_map) {
            var iter = ctx_map.find(id);
            if (iter != nilptr){    
                lctx = iter.getValue();
            }
        }
        
        //通过context 发送给对应接收端
        if (lctx != 0){
            //_system_.consoleWrite("send Content = " + new String(data, offset, len) + "id = " + id + "\n");
            _unsi.getAsyncDirectOutput().dataDeparture(this,lctx,0,data, offset, len);
        }
        //否则没有找到 说明已经阻断 不处理
    }
    
    /** 服务器通过RCP通知有新连接接入, id为链接标号， 本地要创建对应链接 */
    public void connect(int id){
            /** @这里填你要转发的源服务器地址  比如你的SVN服务器地址和端口 */
        _unsi.getAsyncDirectOutput().newInstance(this,serverHost, serverPort, id); 
    }

    /*** 新连接被创建的回调 克隆一个context ，以便后续使用， @caution 注意 克隆的context 需要手动释放*/
	bool newInstance(AsyncOutput output, int type, long bind, long context)override{
        if (_client != nilptr){
            int id = output.getInstanceId(context);
            synchronized(ctx_map) {
                ctx_map.put(id,output.cloneContext(context));/*** @caution 注意 克隆的context 需要手动释放*/
            }
            _client.bind(id, bind);
            return true;
        }
		return false;
	}

    /*** unsi 接口上收到数据*/
	bool dataArrives(AsyncOutput output, long context, byte[] data, int offset, int length)override{
        /*** 对数据进行加密， 通过RCP发送给中转服务器 */
        encrypt(data, offset, length);
        _client.onrecv(_unsi.getId(context), data, offset, length);
		return true;
	}

    /*** unsi接口上收到链接断开的事件*/
	bool deleteInstance(AsyncOutput output, long context)override{
        int id = _unsi.getId(context);
        long lctx = 0;
        synchronized(ctx_map) {
            var iter = ctx_map.find(id);
            if (iter != nilptr){    
                lctx = iter.getValue();
                ctx_map.remove(iter);
            }
        }
        if (lctx != 0){ // 如果有关联  则释放句柄， 通知服务器关闭
            output.releaseContext(lctx);
            _client.onSVNClose(id);
        }
		return true;
	}

    // RCP通知链接关闭 
    public void close(int lid){
        long hctx = 0;
        synchronized(ctx_map) {
            var iter = ctx_map.find(lid);
            if (iter != nilptr){
                hctx = iter.getValue();
                ctx_map.remove(iter);
            }
        }
        if (hctx != 0){ // 如果有关联  则释放句柄， 关闭本地连接
            _unsi.getAsyncDirectOutput().deleteInstance(this, hctx);
            _unsi.getAsyncDirectOutput().releaseContext(hctx);
        }
    }
    
	bool inactiveTimeout(AsyncOutput output, long context)override{
		return true;
	}
};